package app

import (
	"crypto/hmac"
	"crypto/sha256"
	"fmt"
	"github.com/wendy512/go-iecp5/asdu"
	"github.com/wendy512/iec104/client"
)

type IecMyclient struct {
}

func NewIecMyclient() *IecMyclient {
	return &IecMyclient{}
}

// OnInterrogation 总召唤回复
func (c *IecMyclient) OnInterrogation(packet *asdu.ASDU) error {
	addr, value := packet.GetInterrogationCmd()
	fmt.Printf("interrogation reply, addr: %d, value: %d\n", addr, value)
	return nil
}

// OnCounterInterrogation 总计数器回复
func (c *IecMyclient) OnCounterInterrogation(packet *asdu.ASDU) error {
	addr, value := packet.GetCounterInterrogationCmd()
	fmt.Printf("counter interrogation reply, addr: %d, request: 0x%02X, rreeze: 0x%02X\n",
		addr, value.Request, value.Freeze)
	return nil
}

// OnRead 读定值回复
func (c *IecMyclient) OnRead(packet *asdu.ASDU) error {
	return c.OnASDU(packet)
}

// OnTestCommand 测试下发回复
func (c *IecMyclient) OnTestCommand(packet *asdu.ASDU) error {
	addr, value := packet.GetTestCommand()
	fmt.Printf("test cmd reply, addr: %d, value: %t\n", addr, value)
	return nil
}

// OnClockSync 时钟同步回复
func (c *IecMyclient) OnClockSync(packet *asdu.ASDU) error {
	addr, value := packet.GetClockSynchronizationCmd()
	fmt.Printf("clock sync reply, addr: %d, value: %d\n", addr, value.UnixMilli())
	return nil
}

// OnResetProcess 进程重置回复
func (c *IecMyclient) OnResetProcess(packet *asdu.ASDU) error {
	addr, value := packet.GetResetProcessCmd()
	fmt.Printf("reset process reply, addr: %d, value: 0x%02X\n", addr, value)
	return nil
}

// OnDelayAcquisition 延迟获取回复
func (c *IecMyclient) OnDelayAcquisition(packet *asdu.ASDU) error {
	addr, value := packet.GetDelayAcquireCommand()
	fmt.Printf("delay acquisition reply, addr: %d, value: %d\n", addr, value)
	return nil
}

// OnASDU 数据正体
func (c *IecMyclient) OnASDU(packet *asdu.ASDU) error {
	// 读取设备数据
	switch client.GetDataType(packet.Type) {
	case client.SinglePoint:
		c.onSinglePoint(packet)
	case client.DoublePoint:
		c.onDoublePoint(packet)
	case client.MeasuredValueScaled:
		c.onMeasuredValueScaled(packet)
	case client.MeasuredValueNormal:
		c.onMeasuredValueNormal(packet)
	case client.StepPosition:
		c.onStepPosition(packet)
	case client.BitString32:
		c.onBitString32(packet)
	case client.MeasuredValueFloat:
		c.onMeasuredValueFloat(packet)
	case client.IntegratedTotals:
		c.onIntegratedTotals(packet)
	case client.EventOfProtectionEquipment:
		c.onEventOfProtectionEquipment(packet)
	case client.PackedStartEventsOfProtectionEquipment:
		c.onPackedStartEventsOfProtectionEquipment(packet)
	case client.PackedOutputCircuitInfo:
		c.onPackedOutputCircuitInfo(packet)
	case client.PackedSinglePointWithSCD:
		c.onPackedSinglePointWithSCD(packet)
	default:
		return nil
	}

	return nil
}

func (c *IecMyclient) onSinglePoint(packet *asdu.ASDU) {
	// [M_SP_NA_1], [M_SP_TA_1] or [M_SP_TB_1] 获取单点信息信息体集合
	for _, p := range packet.GetSinglePoint() {
		fmt.Printf("single point, ioa: %d, value: %v\n", p.Ioa, p.Value)
	}
}

func (c *IecMyclient) onDoublePoint(packet *asdu.ASDU) {
	// [M_DP_NA_1], [M_DP_TA_1] or [M_DP_TB_1] 获得双点信息体集合
	for _, p := range packet.GetDoublePoint() {
		fmt.Printf("double point, ioa: %d, value: %v\n", p.Ioa, p.Value)
	}
}

func (c *IecMyclient) onMeasuredValueScaled(packet *asdu.ASDU) {
	// [M_ME_NB_1], [M_ME_TB_1] or [M_ME_TE_1] 获得测量值，标度化值信息体集合
	for _, p := range packet.GetMeasuredValueScaled() {
		fmt.Printf("measured value scaled, ioa: %d, value: %v\n", p.Ioa, p.Value)
	}
}

func (c *IecMyclient) onMeasuredValueNormal(packet *asdu.ASDU) {
	// [M_ME_NA_1], [M_ME_TA_1],[ M_ME_TD_1] or [M_ME_ND_1] 获得测量值,规一化值信息体集合
	for _, p := range packet.GetMeasuredValueNormal() {
		fmt.Printf("measured value normal, ioa: %d, value: %v\n", p.Ioa, p.Value)
	}
}

func (c *IecMyclient) onStepPosition(packet *asdu.ASDU) {
	// [M_ST_NA_1], [M_ST_TA_1] or [M_ST_TB_1] 获得步位置信息体集合
	for _, p := range packet.GetStepPosition() {
		// state：false: 设备未在瞬变状态 true： 设备处于瞬变状态
		fmt.Printf("step position, ioa: %d, state: %t, value: %d\n", p.Ioa, p.Value.HasTransient, p.Value.Val)
	}
}

func (c *IecMyclient) onBitString32(packet *asdu.ASDU) {
	// [M_ME_NC_1], [M_ME_TC_1] or [M_ME_TF_1].获得测量值,短浮点数信息体集合
	for _, p := range packet.GetMeasuredValueFloat() {
		fmt.Printf("bigtstring32, ioa: %d, value: %v\n", p.Ioa, p.Value)
	}
}

func (c *IecMyclient) onMeasuredValueFloat(packet *asdu.ASDU) {
	// [M_ME_NC_1], [M_ME_TC_1] or [M_ME_TF_1].获得测量值,短浮点数信息体集合
	for _, p := range packet.GetMeasuredValueFloat() {
		fmt.Printf("measured value float, ioa: %d, value: %v\n", p.Ioa, p.Value)
	}
}

func (c *IecMyclient) onIntegratedTotals(packet *asdu.ASDU) {
	// [M_IT_NA_1], [M_IT_TA_1] or [M_IT_TB_1]. 获得累计量信息体集合
	for _, p := range packet.GetIntegratedTotals() {
		fmt.Printf("integrated totals, ioa: %d, count: %d, SQ: 0x%02X, CY: %t, CA: %t, IV: %t\n",
			p.Ioa, p.Value.CounterReading, p.Value.SeqNumber, p.Value.HasCarry, p.Value.IsAdjusted, p.Value.IsInvalid)
	}
}

func (c *IecMyclient) onEventOfProtectionEquipment(packet *asdu.ASDU) {
	// [M_EP_TA_1] [M_EP_TD_1] 获取继电器保护设备事件信息体
	for _, p := range packet.GetEventOfProtectionEquipment() {
		fmt.Printf("event of protection equipment, ioa: %d, event: %d, qdp: %d, mesc: %d, time: %d\n",
			p.Ioa, p.Event, p.Qdp, p.Msec, p.Time.UnixMilli())
	}
}

func (c *IecMyclient) onPackedStartEventsOfProtectionEquipment(packet *asdu.ASDU) {
	// [M_EP_TB_1] [M_EP_TE_1] 获取继电器保护设备事件信息体
	p := packet.GetPackedStartEventsOfProtectionEquipment()
	fmt.Printf("packed start events of protection equipment, ioa: %d, event: %d, qdp: %d, mesc: %d, time: %d\n",
		p.Ioa, p.Event, p.Qdp, p.Msec, p.Time.UnixMilli())
}

func (c *IecMyclient) onPackedOutputCircuitInfo(packet *asdu.ASDU) {
	// [M_EP_TC_1] [M_EP_TF_1] 获取继电器保护设备成组输出电路信息信息体
	p := packet.GetPackedOutputCircuitInfo()
	fmt.Printf("packed Output circuit, ioa: %d, qci: %d, qdp: %d, mesc: %d, time: %d\n",
		p.Ioa, p.Oci, p.Qdp, p.Msec, p.Time.UnixMilli())
}

func (c *IecMyclient) onPackedSinglePointWithSCD(packet *asdu.ASDU) {
	// [M_PS_NA_1]. 获得带变位检出的成组单点信息
	for _, p := range packet.GetPackedSinglePointWithSCD() {
		fmt.Printf("packed single point with SCD, ioa: %d, scd: %d, qds: %d\n", p.Ioa, p.Scd, p.Qds)
	}
}

func (c *IecMyclient) SendControlCommand(ca int, ioa int, value float32) error {
	// 发送设点或遥控命令
	switch {
	case ioa == 4 || ioa == 5: // 设点命令
		return c.SendSetpointCommand(ca, asdu.C_SE_NC_1, asdu.InfoObjAddr(ioa), value)
	case ioa == 6: // 遥控命令
		return c.SendSingleCommand(ca, asdu.C_SC_NA_1, asdu.InfoObjAddr(ioa), value != 0)
	case ioa >= 24 && ioa <= 39: // DO控制
		return c.SendDoubleCommand(ca, asdu.C_DC_NA_1, asdu.InfoObjAddr(ioa), asdu.DoubleCommand(asdu.DPIDeterminedOn))
	}
	return nil
}

func (c *IecMyclient) PollData() {
	// 轮询所有设备数据
	for _, ca := range []int{1, 2, 3, 4, 5, 10, 11, 12} {
		c.SendInterrogationCmd(ca)
	}
}

func (c *IecMyclient) SendInterrogationCmd(ca int) error {
	// 创建总召唤命令
	// 实际实现取决于您的客户端库的具体实现方式
	// 示例: return asdu.InterrogationCmd(ca, asdu.QOIStation)
	return nil
}

func (c *IecMyclient) SendDoubleCommand(ca int, typeID asdu.TypeID, ioa asdu.InfoObjAddr, dpValue asdu.DoubleCommand) error {
	// 创建双点命令信息
	cmd := asdu.DoubleCommandInfo{
		Ioa:   ioa,
		Value: dpValue,
		Qoc:   asdu.QualifierOfCommand{},
	}
	fmt.Println(cmd)
	// 发送命令
	// 实际实现取决于您的客户端库的具体实现方式
	return nil
}

// 添加在IecMyclient结构体方法中
func (c *IecMyclient) SendSingleCommand(ca int, typeID asdu.TypeID, ioa asdu.InfoObjAddr, value bool) error {
	// 创建单点命令信息
	cmd := asdu.SingleCommandInfo{
		Ioa:   ioa,
		Value: value,
		Qoc:   asdu.QualifierOfCommand{},
	}
	fmt.Println(cmd)
	// 发送命令

	return nil //asdu.Single()(ca, typeID, cmd)
}

// 同时需要添加SendSetpointCommand方法
func (c *IecMyclient) SendSetpointCommand(ca int, typeID asdu.TypeID, ioa asdu.InfoObjAddr, value float32) error {
	// 这里需要实现发送设点命令的逻辑
	// 实际实现取决于您的客户端库的具体实现方式

	//asdu.Single()
	return nil
}

// generateAuthResponse 生成HMAC-SHA256认证响应
func generateAuthResponse(challenge []byte, username string, password string) []byte {
	// 1. 组合用户名和密码作为密钥
	secret := []byte(username + ":" + password)

	// 2. 创建HMAC-SHA256哈希
	h := hmac.New(sha256.New, secret)
	h.Write(challenge)

	// 3. 返回HMAC结果
	return h.Sum(nil)
}

// 在IecMyclient中添加认证处理方法
func (c *IecMyclient) OnAuthChallenge(packet *asdu.ASDU) error {
	var username, password string
	challenge := []byte{}
	//challenge := packet.GetChallenge()
	// 使用存储的密码生成HMAC-SHA256响应
	response := generateAuthResponse(challenge, username, password)
	// 发送S_RP_NA_1响应
	fmt.Println(string(response))
	return nil
}

func (c *IecMyclient) OnAuthError(packet *asdu.ASDU) error {
	//errCode := packet.GetErrorCode()
	// 处理错误代码
	return nil
}

func (c *IecMyclient) OnUserStatus(packet *asdu.ASDU) error {
	//status := packet.GetUserStatus()
	// 处理用户状态变更
	return nil
}
